#include "input.h"

void init_input() {

}

void cleanup_input(cr_button_node *root) {
    destroy_buttons(root);
}

button construct_button(char id, int x, int y, int w, int h, void (*callback)(void* data), cr_drawable d[2]) {
    button button;

    button.id = id;
    button.x = x;
    button.y = y;
    button.w = w;
    button.h = h;
    button.callback = callback;
    button.visual[0].texture = d[0].texture;
    button.visual[1].texture = d[1].texture;
    button.visual[0].rect = d[0].rect;
    button.visual[1].rect = d[1].rect;

    return button;
}

void update_button(cr_button_node *root, char id, int x, int y, int w, int h, void (*callback)(void* data), cr_drawable visual[2], bool update_area, bool update_callback, bool update_visual) {
    /* if user wants to update nothing */
    if (!update_area && !update_callback && !update_visual)
        return;

    /* iterate buttons to handle possible event */
    cr_button_node *node = root;
    while (node != NULL) {
        cr_button_node *current = node;
        node = node->next;
        if (current->payload.id == id) {
            if (update_area) {
                current->payload.x = x;
                current->payload.y = y;
                current->payload.w = w;
                current->payload.h = h;
                if (DEBUG)
                    printf("area of button with id %i updated\n", id);
            }
            if (update_callback) {
                current->payload.callback = callback;
                if (DEBUG)
                    printf("callback of button with id %i updated\n", id);
            }
            if (update_visual) {
                if (current->payload.visual[0].texture != NULL)
                    destroy_cr_drawable(&current->payload.visual[0]);
                if (current->payload.visual[1].texture != NULL)
                    destroy_cr_drawable(&current->payload.visual[1]);
                current->payload.visual[0] = visual[0];
                current->payload.visual[1] = visual[1];
                if (DEBUG)
                    printf("visual of button with id %i updated\n", id);
            }
            break;
        }
    }
}

void register_mousedown_event(cr_button_node **root, cr_button_node **tail, button b) {
    /* special case root node */
    if (*root == NULL) {
        *root = malloc(sizeof(cr_button_node));
        if (*root == NULL) {
            fprintf(stderr, "error: error allocating memory for cr_button_node\n");
            exit(EXIT_FAILURE);
        }

        /* set values */
        (*root)->payload = b;
        (*root)->next = NULL;

        /* set tail */
        *tail = *root;
        return;
    }

    (*tail)->next = malloc(sizeof(cr_button_node));
    (*tail) = (*tail)->next;
    (*tail)->payload = b;
    (*tail)->next = NULL;
}

void register_new_button_visual(cr_button_node **root) {

}

void destroy_buttons(cr_button_node *root) {
    cr_button_node *node = root;
    while (node != NULL) {
        cr_button_node *current = node;
        node = node->next;
        /* free all resources of button */
        if (current->payload.visual[0].texture != NULL)
            destroy_cr_drawable(&current->payload.visual[0]);
        if (current->payload.visual[1].texture != NULL)
            destroy_cr_drawable(&current->payload.visual[1]);
        free(current);
    }
}

void get_input(bool *update, cr_button_node *root, int *window_w, int *window_h, int *border) {
    SDL_Event event;

    while (SDL_PollEvent(&event)) {
        switch (event.type) {
            case SDL_QUIT:
                exit(EXIT_SUCCESS);
                break;

            case SDL_WINDOWEVENT: {
                switch (event.window.event) {
                    case SDL_WINDOWEVENT_SIZE_CHANGED: {
                        *window_w = event.window.data1;
                        *window_h = event.window.data2;
                        *border = (event.window.data1 + event.window.data2) * 0.034;
                        /* all textures need to be remade */
                        for (int i = 0; i < TOKEN_ENUM_SIZE; i++)
                            update[i] = true;
                        break;
                    }
                }
                break;
            }

            case SDL_KEYDOWN: {
                switch (event.key.keysym.sym) {
                    case SDLK_ESCAPE:
                        if (event.key.keysym.mod & KMOD_CTRL)
                            exit(EXIT_SUCCESS);
                        break;
                    case SDLK_q:
                        if (event.key.keysym.mod & KMOD_CTRL)
                            exit(EXIT_SUCCESS);
                        break;
                    case SDLK_F4:
                        if (event.key.keysym.mod & KMOD_ALT)
                            exit(EXIT_SUCCESS);
                        break;
                    case SDLK_w:
                        break;
                    case SDLK_a:
                        break;
                    case SDLK_s:
                        break;
                    case SDLK_d: {
                        break;
                    }
                    default:
                        break;
                }
                break;
            }

            case SDL_MOUSEBUTTONDOWN: {
                /* query mouse press */
                int x, y;
                SDL_GetMouseState(&x, &y);
                if (DEBUG)
                    printf("mouse button down %i %i\n", x, y);

                /* iterate buttons to handle possible event */
                cr_button_node *node = root;
                while (node != NULL) {
                    cr_button_node *current = node;
                    node = node->next;
                    if (DEBUG)
                        printf("button { x %i, y %i, w %i, h %i, callback %p, texture1 %p, texture2 %p } @ %p\n", current->payload.x, current->payload.y, current->payload.w, current->payload.h, current->payload.callback, current->payload.visual[0].texture, current->payload.visual[1].texture, current);
                    /* collision detection lol */
                    if (x >= current->payload.x &&
                        y >= current->payload.y &&
                        x < current->payload.x + current->payload.w &&
                        y < current->payload.y + current->payload.h) {
                        (*current->payload.callback)(NULL);
                    }
                }
                break;
            }

            default:
                break;
        }
    }
}